home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / scheme / pcscheme / geneva / sources.exe / SOURCES / LISP / DEFMACRO.LSP < prev    next >
Encoding:
Lisp/Scheme  |  1990-09-08  |  21.1 KB  |  584 lines

  1. ;; PC Scheme Common Lisp Compatibility Package
  2. ;;
  3. ;; (c) Copyright 1990 Carl W. Hoffman.  All rights reserved.
  4. ;;
  5. ;; This file may be freely copied, distributed, or modified for non-commercial
  6. ;; use provided that this copyright notice is not removed.  For further
  7. ;; information about other utilities for Common Lisp or Scheme, contact the
  8. ;; following address:
  9. ;;
  10. ;;   Carl W. Hoffman, 363 Marlborough Street, Boston, MA 02115, U.S.A.
  11. ;;   Internet: CWH@AI.MIT.EDU    CompuServe: 76416,3365    Fax: 617-262-4284
  12.  
  13. ;; DEFMACRO, DOTIMES, DOLIST, DEFUN
  14. ;; SETQ, SETF, PUSH, POP, INCF, DECF
  15. ;; DESCRIBE, ARGLIST
  16.  
  17. ;; To do:
  18. ;;   -P variables for DEFUN &OPTIONAL
  19. ;;   Define LAMBDA as a macro so that isolated LAMBDA expressions
  20. ;;     can have &OPTIONAL, etc.
  21. ;;   PSETQ, PSETF
  22. ;;   Check for too many arguments to function when &OPTIONAL used but
  23. ;;     not &REST.
  24. ;;   DESTRUCTURING-BIND, destructuring DEFMACRO
  25. ;;   Allow . as synonym for &REST in DEFMACRO and DEFUN
  26. ;;   DEFSETF (then use with PICT.SCM XSET/XREF)
  27.  
  28. (defun-clcp symbol-append (&rest symbols)
  29.   (intern (apply string-append (mapcar string symbols))))
  30.  
  31. (defun-clcp %%check-defmacro-args (pattern form)
  32.   (let ((optional? nil)
  33.         (rest? nil))
  34.     (do ((patternl pattern)
  35.          (forml form))
  36.         ((or rest?
  37.              (and optional? (null forml))
  38.              (and (null patternl) (null forml))))
  39.       (when (null patternl)
  40.         (error "The form ~S has more arguments than the DEFMACRO pattern ~S."
  41.                form pattern))
  42.       (let ((var (car patternl)))
  43.         (cond ((eq var '&whole)
  44.                (pop patternl)
  45.                (pop patternl))
  46.               ((eq var '&environment)
  47.                (pop patternl)
  48.                (pop patternl))
  49.               ((eq var '&optional)
  50.                (setq optional? t)
  51.                (pop patternl))
  52.               ((member var '(&rest &body))
  53.                (setq rest? t))
  54.               (else
  55.                (when (null forml)
  56.                  (error "The form ~S has fewer arguments than the DEFMACRO ~
  57.                          pattern ~S"
  58.                         form pattern))
  59.                (pop patternl)
  60.                (pop forml)
  61.                ))))))
  62.  
  63. (defun-clcp %%construct-defmacro-bindings (bvl)
  64.   (let ((optional? nil)
  65.         (rest? nil)
  66.         (result ()))
  67.     (do ((varl bvl (cdr varl)))
  68.         ((null varl))
  69.       (let ((var (car varl)))
  70.         (cond ((eq var '&whole)
  71.                (unless (cdr varl)
  72.                  (error "No tokens follow the &WHOLE keyword."))
  73.                (pop varl)
  74.                (setq var (car varl))
  75.                (push `(,var defmacro-whole-form) result))
  76.               ((eq var '&environment)
  77.                (pop varl)
  78.                (setq var (car varl))
  79.                (push `(,var nil) result))
  80.               (else
  81.                (when rest?
  82.                  (error "The additional tokens ~S follow ~
  83.                          a &REST or &BODY variable."
  84.                         bvl))
  85.                (cond ((eq var '&optional)
  86.                       (when optional?
  87.                         (error "The &OPTIONAL keyword appears twice in ~S."
  88.                                bvl))
  89.                       (setq optional? t)
  90.                       (unless (cdr varl)
  91.                         (error "No tokens follow the &OPTIONAL keyword in ~S."
  92.                                bvl)))
  93.                      ((member var '(&rest &body))
  94.                       (setq rest? t)
  95.                       (pop varl)
  96.                       (unless varl
  97.                         (if (eq var '&rest)
  98.                             (error "No variable follows the &REST keyword.")
  99.                             (error "No variable follows the &BODY keyword.")))
  100.                       (setq var (car varl))
  101.                       (push `(,var defmacro-form) result))
  102.                      (optional?
  103.                       (when (and (listp var) (caddr var))
  104.                         (push `(,(caddr var) (not (null defmacro-form)))
  105.                               result))
  106.                       (push
  107.                         (if (listp var)
  108.                            `(,(car var)
  109.                               (if (null defmacro-form)
  110.                                   ,(cadr var)
  111.                                   (pop defmacro-form)))
  112.                            `(,var (,(if (cdr varl) 'pop 'car) defmacro-form)))
  113.                         result))
  114.                      (else
  115.                       (push `(,var (,(if (cdr varl) 'pop 'car) defmacro-form))
  116.                             result)))))))
  117.     (nreverse result)))
  118.  
  119. (defvar *include-arglist* t)
  120.  
  121. ;; This implementation captures the variables DEFMACRO-WHOLE-FORM and
  122. ;; DEFMACRO-FORM.  PP incorrectly displays this function.  The ". ,body"
  123. ;; confuses it.
  124.  
  125. (defmacro defmacro (name bvl &body body)
  126.   (unless (symbolp name)
  127.     (error "The first argument to DEFMACRO, ~S, was not a symbol." name))
  128.   (unless (listp bvl)
  129.     (error "The second argument to DEFMACRO, ~S, was not a list." bvl))
  130.   ;; PC Scheme barfs if LET or LET* has an empty body.
  131.   (cond ((null body)
  132.          (setq body '(nil)))
  133.         ((stringp (car body))
  134.          (pop body)))
  135.   (let ((function-name (symbol-append 'expand- name)))
  136.     `(prog2
  137.        (define (,function-name defmacro-whole-form)
  138.          (scheme-let ((defmacro-form (cdr defmacro-whole-form)))
  139.            (%%check-defmacro-args ',bvl defmacro-form)
  140.            . ,(let ((bindings (%%construct-defmacro-bindings bvl)))
  141.                 (if (null bindings)
  142.                     body
  143.                     `((scheme-let* ,bindings . ,body))))))
  144.        (macro ,name ,function-name)
  145.        ,@ (if *include-arglist*
  146.               `((putprop ',name ',bvl 'arglist))))))
  147.  
  148. ;; SETQ and SETF
  149.  
  150. ;; SET! only allows one variable/value pair.
  151. ;; The return value of SETQ must be the last value assigned.
  152. ;; The return value of SET! is unspecified.
  153. ;; The following implementation of SETQ relies upon the fact that
  154. ;; PC Scheme SET! returns the value assigned.
  155.  
  156. (defun-clcp %%construct-setq (variable value)
  157.   `(set! ,variable ,value))
  158.  
  159. ;; Multi-form syntax definitions such as this one don't work.
  160. ;; Only the most recently seen form remains in effect.
  161. ;; (syntax (setf a b) (set! a b))
  162. ;; (syntax (setf (char s i) c) (string-set! s i c))
  163.  
  164. (defun-clcp %%construct-setf (place value)
  165.   (cond ((symbolp place)
  166.          `(set! ,place ,value))
  167.         ((not (consp place))
  168.          (error "The first argument to SETF, ~S, was not a symbol or form."
  169.                 place))
  170.         (else
  171.          (let ((fcn       (first place))
  172.                (thing     (second place))
  173.                (subscript (third place)))
  174.            (cond
  175.              ((eq fcn 'fluid)
  176.               `(set! ,place ,value))
  177.              ((member fcn '(car first))
  178.               `(rplaca ,thing ,value))
  179.              ((member fcn '(cdr rest))
  180.               `(rplacd ,thing ,value))
  181.              ((member fcn '(cadr second))
  182.               `(rplaca (cdr ,thing) ,value))
  183.              ((eq fcn 'cddr)
  184.               `(rplacd (cdr ,thing) ,value))
  185.              ((member fcn '(char string-ref))
  186.               `(string-set! ,thing ,subscript ,value))
  187.              ((member fcn '(svref vector-ref))
  188.               `(vector-set! ,thing ,subscript ,value))
  189.              ((eq fcn 'aref)
  190.               `(%%setf-aref ,value ,thing ,subscript))
  191.              ((member fcn '(get getprop))
  192.               `(putprop ,thing ,value ,subscript))
  193.              ((eq fcn 'macro-function)
  194.               `(putprop ,thing ,value 'pcs*macro))
  195.              ((eq fcn 'primop-handler)
  196.               `(putprop ,thing ,value 'pcs*primop-handler))
  197.              ;; An accessor defined with DEFINE-STRUCTURE will have
  198.              ;; a PCS*PRIMOP-HANDLER property.  Check this after
  199.              ;; checking for everything else.
  200.              ((get fcn 'pcs*primop-handler)
  201.               `(set! ,place ,value))
  202.              (else
  203.               (error "The first argument to SETF, ~S, was unrecognized."
  204.                      place)))))))
  205.  
  206. (defun-clcp %%construct-setq-setf (constructor variable value vars-and-vals)
  207.   (if (null vars-and-vals)
  208.       (constructor variable value)
  209.       (let ((result (list `(set! ,variable ,value))))
  210.         (do ((l vars-and-vals))
  211.             ((null l))
  212.           (when (null (cdr l))
  213.             (error "The last variable in a SETQ or SETF form, ~S, ~
  214.                     doesn't have a matching value."
  215.               (car l)))
  216.           (push (constructor (car l) (cadr l)) result)
  217.           (setq l (cddr l)))
  218.         `(begin . ,(nreverse result)))))
  219.  
  220. (defmacro setq (variable value &rest vars-and-vals)
  221.   (%%construct-setq-setf %%construct-setq variable value vars-and-vals))
  222.  
  223. (defmacro setf (place value &rest places-and-vals)
  224.   (%%construct-setq-setf %%construct-setf place value places-and-vals))
  225.  
  226. ;; These macros need to "once only" PLACE.  Also, as Steele points out,
  227. ;; PUSH and PUSHNEW could be implemented more efficiently.
  228.  
  229. (defmacro push (item place)
  230.   `(setf ,place (cons ,item ,place)))
  231.  
  232. (defmacro pushnew (item place)
  233.   `(setf ,place (adjoin ,item ,place)))
  234.  
  235. (defmacro pop (place)
  236.   `(prog1 (car ,place)
  237.           (setf ,place (cdr ,place))))
  238.  
  239. (defmacro incf (place &optional amount)
  240.   `(setf ,place
  241.          ,(if amount `(+ ,place ,amount) `(1+ ,place))))
  242.  
  243. (defmacro decf (place &optional amount)
  244.   `(setf ,place
  245.          ,(if amount `(- ,place ,amount) `(1-, place))))
  246.  
  247. ;; It would be nice to use (VALUES) rather than NIL here, but
  248. ;; (EVAL (VALUES)) causes an error.
  249.  
  250. (defmacro comment (&body ignore) nil)
  251.  
  252. ;; This should be implemented as a function, not a special form.
  253.  
  254. (defmacro funcall (fcn &rest arguments)
  255.   (cons fcn arguments))
  256.  
  257. ;; This implements RESULTFORM as specified by Common Lisp, even though
  258. ;; the feature appears to be useless.
  259.  
  260. ;; This should use destructuring DEFMACRO and N-ary <=.
  261.  
  262. (defmacro dolist (var-list &body body)
  263.   (unless (and (listp var-list)
  264.                (<= 2 (length var-list))
  265.                (<= (length var-list) 3))
  266.     (error "The first argument to DOLIST was ~S, which does not match ~
  267.             the pattern (VAR LISTFORM) or ~
  268.             the pattern (VAR LISTFORM RESULTFORM)."
  269.            bvl))
  270.   ;; This should use DESTRUCTURING-BIND.
  271.   (let ((var        (car var-list))
  272.         (listform   (cadr var-list))
  273.         (resultform (caddr var-list)))
  274.     (unless (symbolp var)
  275.       (error "The binding variable, ~S, was not a symbol." var))
  276.     `(block nil
  277.        (for-each (lambda (,var) . ,body) ,listform)
  278.        ,(if (null resultform)
  279.             'nil
  280.             `(lambda ((,var nil)) ,resultform)))))
  281.  
  282. (defun-clcp %%dotimes (thunk count)
  283.   (do ((i 0 (1+ i)))
  284.       ((>= i count))
  285.     (thunk i)))
  286.  
  287. ;; This should use destructuring DEFMACRO and N-ary <=.
  288.  
  289. (defmacro dotimes (pattern &body body)
  290.   (unless (and (listp pattern)
  291.                (<= 2 (length pattern))
  292.                (<= (length pattern) 3))
  293.     (error "The first argument to DOTIMES was ~S, which does not match ~
  294.             the pattern (VAR COUNTFORM) or ~
  295.             the pattern (VAR COUNTFORM RESULTFORM)."
  296.            bvl))
  297.   (let ((var        (car pattern))
  298.         (countform  (cadr pattern))
  299.         (resultform (caddr pattern)))
  300.     (unless (symbolp var)
  301.       (error "The binding variable, ~S, was not a symbol." var))
  302.     `(block nil
  303.        ,(if (null resultform)
  304.             `(%%dotimes (lambda (,var) . ,body) ,countform)
  305.             `(let ((,var ,countform))
  306.                (%%dotimes (lambda (,var) . ,body) ,var)
  307.                ,resultform)))))
  308.  
  309. (defun macroexpand (form &optional environment)
  310.   (expand-macro form))
  311.  
  312. (defun macroexpand-1 (form &optional environment)
  313.   (expand-macro form))
  314.  
  315. (defun-clcp %%construct-lambda-args (bvl)
  316.   (let ((optional? nil)
  317.         (rest? nil)
  318.         (aux? nil)
  319.         (tail nil)
  320.         (result ()))
  321.     (do ((varl bvl (cdr varl)))
  322.         ((null varl))
  323.       (let ((var (car varl)))
  324.         (cond
  325.           (aux?
  326.             (when (memq var '(&optional &rest &aux))
  327.               (error "The token following &AUX, ~S, is an &keyword, which ~
  328.                       cannot be the name of a local variable."
  329.                      var))
  330.             (cond ((symbolp var))
  331.                   ((consp var)
  332.                    (unless (= (length var) 2)
  333.                      (error "The &AUX declaration, ~S, ~
  334.                              is not a list of length 2."
  335.                             var)))
  336.                   (else
  337.                     (error "The token following the &AUX keyword, ~S, ~
  338.                             was not a symbol or list of length 2."
  339.                            var))))
  340.           ((eq var '&aux)
  341.            (setq aux? t))
  342.           (else
  343.             (when rest?
  344.               (error "Additional tokens follow &REST variable" bvl))
  345.             (cond
  346.               ((eq var '&optional)
  347.                (when optional?
  348.                  (error "&OPTIONAL keyword appears twice" bvl))
  349.                (setq optional? t)
  350.                (unless (cdr varl)
  351.                  (error "No tokens follow &OPTIONAL keyword" bvl))
  352.                (setq tail (gensym)))
  353.               ((eq var '&rest)
  354.                (setq rest? t)
  355.                (pop varl)
  356.                (unless varl
  357.                  (error "No tokens follow &REST keyword" bvl))
  358.                (setq var (car varl))
  359.                (unless (symbolp var)
  360.                  (error "&REST declaration must be a symbol" var))
  361.                (unless tail
  362.                  (setq tail var)))
  363.               ;; The token isn't an & keyword.
  364.               (optional?
  365.                 (cond
  366.                   ((symbolp var))
  367.                   ((consp var)
  368.                    (unless (= (length var) 2)
  369.                      (error
  370.                        "The &OPTIONAL declaration, ~S, was not a list ~
  371.                         of length 2."
  372.                        var)))
  373.                   (else
  374.                     (error
  375.                       "&OPTIONAL declaration must be symbols or lists" 
  376.                       var))))
  377.               ((symbolp var)
  378.                (push var result))
  379.               (else
  380.                 (error "Required variable declarations must be symbols"
  381.                        var)))))))
  382.     (dolist (r result)
  383.       (push r tail))
  384.     tail))
  385.  
  386. (defun-clcp %%construct-lambda-bindings (bvl tail)
  387.   (let ((optional? nil)
  388.         (rest? nil)
  389.         (aux? nil)
  390.         (result ()))
  391.     (do ((varl bvl (cdr varl)))
  392.         ((null varl))
  393.       (let ((var (car varl)))
  394.         (cond (aux?
  395.                (push (if (symbolp var) `(,var nil) var) result))
  396.               ((eq var '&aux)
  397.                (setq aux? t))
  398.               ((eq var '&optional)
  399.                (setq optional? t))
  400.               ((eq var '&rest)
  401.                (setq rest? t))
  402.               (rest?
  403.                (when optional?
  404.                  (push `(,var ,tail) result)))
  405.               ((not optional?))
  406.               (else
  407.                (let ((next (if (cdr varl) 'pop 'car)))
  408.                  (push
  409.                    (if (symbolp var)
  410.                        `(,var (,next ,tail))
  411.                        `(,(car var) (if ,tail (,next ,tail) ,(cadr var))))
  412.                    result))))))
  413.     (nreverse result)))
  414.  
  415. (defun-clcp %%construct-lambda (block-name bvl body)
  416.   ;; Discard declarations and the documentation string for now.
  417.   (let ((documentation-seen? nil))
  418.     (loop
  419.       (if (not (consp body))
  420.           (return)
  421.           (let ((form (car body)))
  422.             (cond
  423.               ((eq form 'declare)
  424.                (pop body))
  425.               ((stringp form)
  426.                (when (null (cdr body))
  427.                  (return))
  428.                (when documentation-seen?
  429.                  (error
  430.                    "Only one documentation string allowed per LAMBDA."))
  431.                (pop body)
  432.                (setq documentation-seen? t))
  433.               (else
  434.                 (return)))))))
  435.   ;; PC Scheme barfs if LET or LET* has an empty body.
  436.   (when (null body)
  437.     (setq body '(nil)))
  438.   (let* ((args
  439.            (%%construct-lambda-args bvl))
  440.          (bindings
  441.            (%%construct-lambda-bindings bvl 
  442.              (if (symbolp args) args (cdr (last args)))))
  443.          (definition nil))
  444.     (when bindings
  445.       (setq body `((let* ,bindings . ,body))))
  446.     ;; The compiler doesn't optimize this out when there is
  447.     ;; no RETURN-FROM so we will have to map over the body
  448.     ;; and do so ourselves.
  449.     (when block-name
  450.       (setq body `((block ,block-name . ,body))))
  451.     (cons args body)))
  452.  
  453. (defun-clcp %%defun (name bvl body definer block-name arglist?)
  454.   (unless (symbolp name)
  455.     (error "The first argument to DEFUN, ~A, was not a symbol." name))
  456.   (unless (listp bvl)
  457.     (error "The second argument to DEFUN, ~A, was not a list." bvl))
  458.   (let ((definition (%%construct-lambda block-name bvl body)))
  459.     (setq definition
  460.           `(,definer ,(cons name (car definition)) . ,(cdr definition)))
  461.     (if (and arglist? *include-arglist*)
  462.         `(begin (putprop ',name ',bvl 'arglist) ,definition)
  463.         definition)))
  464.  
  465. (defmacro defun (name bvl &body body)
  466.   (%%defun name bvl body
  467.            'define name t))
  468.  
  469. (defmacro defun-inline (name bvl &body body)
  470.   (%%defun name bvl body
  471.            'define-integrable nil t))
  472.  
  473. (defmacro defun-clcp (name bvl &body body)
  474.   (%%defun name bvl body
  475.            'define nil nil))
  476.  
  477. (defmacro defun-clcp-inline (name bvl &body body)
  478.   (%%defun name bvl body
  479.            'define-integrable nil nil))
  480.  
  481. ;; This should check that (CAR DEF) is a symbol and (CADR DEF) is a list.
  482.  
  483. (defun-clcp %%make-flet-bindings (let-type definitions body)
  484.   `(,let-type
  485.       ,(map (lambda (def)
  486.               `(,(car def)
  487.                  (lambda . ,(%%construct-lambda nil (cadr def) (cddr def)))))
  488.             definitions)
  489.       . ,body))
  490.  
  491. (defmacro flet (definitions &body body)
  492.   (%%make-flet-bindings 'let definitions body))
  493.  
  494. (defmacro labels (definitions &body body)
  495.   (%%make-flet-bindings 'letrec definitions body))
  496.  
  497. (defconstant lambda-list-keywords
  498.   '(&optional &rest &key &allow-other-keys &aux &body &whole &environment))
  499.  
  500. (defconstant lambda-parameters-limit 50)
  501.  
  502. ;; This is not standard CL, it should be.  Make it user visible anyway.
  503.  
  504. (defun arglist (symbol)
  505.   (get symbol 'arglist))
  506.  
  507. (defun-clcp %%describe-symbol (symbol)
  508.   (let ((arglist (arglist symbol))
  509.         (global-binding
  510.           (assq symbol (environment-bindings user-global-environment)))
  511.         (initial-binding
  512.           (assq symbol (environment-bindings user-initial-environment)))
  513.         (macro-function (macro-function symbol))
  514.         (primop-handler (primop-handler symbol)))
  515.     (format t "~&~S is a symbol." symbol)
  516.     (when global-binding
  517.       (format t "~&  Global binding:   ~S" (cdr global-binding)))
  518.     (when initial-binding
  519.       (format t "~&  Initial binding:  ~S" (cdr initial-binding)))
  520.     (when arglist
  521.       (format t "~&  Arglist:          ~S" arglist))
  522.     (when macro-function
  523.       (format t "~&  Macro definition: ~S" macro-function))
  524.     (when primop-handler
  525.       (format t "~&  Primop handler:   ~S" primop-handler))
  526.     (do ((l (symbol-plist symbol) (cddr l))
  527.          (herald? nil))
  528.         ((null l))
  529.       (let ((property (first l)))
  530.         (unless (memq property '(arglist pcs*macro pcs*primop-handler))
  531.           (unless herald?
  532.             (format t "~&  Other properties:")
  533.             (setq herald? t))
  534.           (format t "~&    ~S -> ~S" property (second l)))))))
  535.  
  536. (defun-clcp %%describe-structure (structure class)
  537.   (let ((slots (get class 'defstruct-slots))
  538.         (structure-length (vector-length structure)))
  539.     (format t "~S is an object of type ~A with the following slots:~%"
  540.             structure class)
  541.     (do ((i 1 (1+ i))
  542.          (l slots (cdr l)))
  543.         (nil)
  544.       (when (= i structure-length)
  545.         (unless (null l)
  546.           (error "Structure template has more slots than instance"))
  547.         (return nil))
  548.       (when (null l)
  549.         (error "Structure instance has more slots than template"))
  550.       (let* ((slot (car l))
  551.              (slot-length (string-length (symbol->string slot))))
  552.         (format t "  ~A:" slot)
  553.         (dotimes (i (max 1 (- 25 slot-length)))
  554.           (write-char #\space)))
  555.       (format t "~S~%" (vector-ref structure i)))))
  556.  
  557. (defun-clcp %%describe-list (list)
  558.   (format t "~&~S is a list." list))
  559.  
  560. (defun-clcp %%describe-vector (vector)
  561.   (format t "~&~S is a vector of length ~D." vector (vector-length vector)))
  562.  
  563. (defun-clcp %%describe-environment (environment)
  564.   (format t "~&~S is an environment with ~D bindings."
  565.             environment (length (environment-bindings environment))))
  566.  
  567. (defun-clcp describe (thing)
  568.   (let ((class (%%structurep thing)))
  569.     (cond
  570.       (class
  571.        (%%describe-structure thing class))
  572.       ((symbolp thing)
  573.        (%%describe-symbol thing))
  574.       ((listp thing)
  575.        (%%describe-list thing))
  576.       ((vectorp thing)
  577.        (%%describe-vector thing))
  578.       ((environment? thing)
  579.        (%%describe-environment thing))
  580.       (else
  581.         (display "Cannot describe ")
  582.         (write thing :escape t))))
  583.   (values))
  584.